/*
 * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef PW_LOG_SYS_IO_CMSIS_DRIVER_BACKEND_H_
#define PW_LOG_SYS_IO_CMSIS_DRIVER_BACKEND_H_

#include "pw_log_sys_io_cmsis_driver/config.h"
#include "pw_log_sys_io_cmsis_driver/util.h"
#include "pw_preprocessor/arguments.h"
#include "pw_preprocessor/compiler.h"
#include "pw_preprocessor/concat.h"
#include "pw_preprocessor/util.h"

#ifdef __cplusplus
extern "C" {
#endif

// Private function reserved for PW_HANDLE_LOG.
void _pw_log_sys_io_cmsis_driver(const char *message, ...) PW_PRINTF_FORMAT(1, 2);

// Private function used to convert the log level into the right string.
static inline const char *_pw_log_sys_io_cmsis_driver_level_name(int level)
{
    switch (level) {
        case PW_LOG_LEVEL_DEBUG:
            return PW_LOG_CMSIS_DRIVER_GREEN PW_LOG_CMSIS_DRIVER_BOLD "DBG" PW_LOG_CMSIS_DRIVER_RESET;
        case PW_LOG_LEVEL_INFO:
            return PW_LOG_CMSIS_DRIVER_MAGENTA PW_LOG_CMSIS_DRIVER_BOLD "INF" PW_LOG_CMSIS_DRIVER_RESET;
        case PW_LOG_LEVEL_WARN:
            return PW_LOG_CMSIS_DRIVER_YELLOW PW_LOG_CMSIS_DRIVER_BOLD "WRN" PW_LOG_CMSIS_DRIVER_RESET;
        case PW_LOG_LEVEL_ERROR:
            return PW_LOG_CMSIS_DRIVER_RED PW_LOG_CMSIS_DRIVER_BOLD "ERR" PW_LOG_CMSIS_DRIVER_RESET;
        case PW_LOG_LEVEL_FATAL:
        case PW_LOG_LEVEL_CRITICAL:
            return PW_LOG_CMSIS_DRIVER_BLACK PW_LOG_CMSIS_DRIVER_BOLD PW_LOG_CMSIS_DRIVER_RED_BG
                "FTL" PW_LOG_CMSIS_DRIVER_RESET;
        default:
            return PW_LOG_CMSIS_DRIVER_GREEN PW_LOG_CMSIS_DRIVER_BOLD "UNK" PW_LOG_CMSIS_DRIVER_RESET;
    }
}

// Format macros
#define PW_LOG_CMSIS_DRIVER_LEVEL_FORMAT  "%s - "
#define PW_LOG_CMSIS_DRIVER_MODULE_FORMAT "%-" PW_STRINGIFY(PW_LOG_CMSIS_DRIVER_MODULE_LENGTH) "s - "

#if PW_LOG_CMSIS_DRIVER_SHOW_FILENAME
#define PW_LOG_CMSIS_DRIVER_FILE_FORMAT "%s:%d - "
#define PW_LOG_CMSIS_DRIVER_FILENAME    PW_LOG_CMSIS_DRIVER_FILE_NAME
#define PW_LOG_CMSIS_DRIVER_LINE        __LINE__
#else
#define PW_LOG_CMSIS_DRIVER_FILE_FORMAT
#define PW_LOG_CMSIS_DRIVER_FILENAME
#define PW_LOG_CMSIS_DRIVER_LINE
#endif // PW_LOG_CMSIS_DRIVER_SHOW_FILENAME

#if PW_LOG_CMSIS_DRIVER_TIMESTAMP
#define PW_LOG_CMSIS_DRIVER_TIMESTAMP_FORMAT "%010" PRIu32 " - "
#define PW_LOG_CMSIS_DRIVER_TIMESTAMP_VALUE  lp_ticker_read()
#else
#define PW_LOG_CMSIS_DRIVER_TIMESTAMP_FORMAT
#define PW_LOG_CMSIS_DRIVER_TIMESTAMP_VALUE
#endif

#define PW_LOG_CMSIS_DRIVER_PREFIX       \
    PW_LOG_CMSIS_DRIVER_TIMESTAMP_FORMAT \
    PW_LOG_CMSIS_DRIVER_LEVEL_FORMAT     \
    PW_LOG_CMSIS_DRIVER_MODULE_FORMAT    \
    PW_LOG_CMSIS_DRIVER_FILE_FORMAT

#define PW_LOG_CMSIS_DRIVER_SUFFIX "\r" // Newline appended by pw::sys_io::WriteLine

// Pigweed log backend implementation
#define PW_HANDLE_LOG(level, flags, LOG_MESSAGE, ...)                                                                 \
    do {                                                                                                              \
        _pw_log_sys_io_cmsis_driver(PW_LOG_CMSIS_DRIVER_PREFIX LOG_MESSAGE PW_LOG_CMSIS_DRIVER_SUFFIX PW_COMMA_ARGS(  \
            PW_LOG_CMSIS_DRIVER_TIMESTAMP_VALUE) PW_COMMA_ARGS(_pw_log_sys_io_cmsis_driver_level_name(level))         \
                                        PW_COMMA_ARGS(PW_LOG_MODULE_NAME) PW_COMMA_ARGS(PW_LOG_CMSIS_DRIVER_FILENAME) \
                                            PW_COMMA_ARGS(PW_LOG_CMSIS_DRIVER_LINE) PW_COMMA_ARGS(__VA_ARGS__));      \
    } while (0)

#ifdef __cplusplus
}
#endif

#endif /* PW_LOG_SYS_IO_CMSIS_DRIVER_BACKEND_H_ */
